/**
 * @fileOverview 组件基类。
 */



var Base = require('../base');
var Uploader = require('../uploader');
var $ = Base.$, _init = Uploader.prototype._init, _destroy = Uploader.prototype.destroy, IGNORE = {}, widgetClass = [];
function isArrayLike(obj) {
    if (!obj) {
        return false;
    }
    var length = obj.length, type = $.type(obj);
    if (obj.nodeType === 1 && length) {
        return true;
    }
    return type === 'array' || type !== 'function' && type !== 'string' && (length === 0 || typeof length === 'number' && length > 0 && length - 1 in obj);
}
function Widget(uploader) {
    this.owner = uploader;
    this.options = uploader.options;
}
$.extend(Widget.prototype, {
    init: Base.noop,
    // 类Backbone的事件监听声明，监听uploader实例上的事件
    // widget直接无法监听事件，事件只能通过uploader来传递
    invoke: function (apiName, args) {
        /*
                {
                    'make-thumb': 'makeThumb'
                }
             */
        var map = this.responseMap;
        // 如果无API响应声明则忽略
        if (!map || !(apiName in map) || !(map[apiName] in this) || !$.isFunction(this[map[apiName]])) {
            return IGNORE;
        }
        return this[map[apiName]].apply(this, args);
    },
    /**
         * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。
         * @method request
         * @grammar request( command, args ) => * | Promise
         * @grammar request( command, args, callback ) => Promise
         * @for  Uploader
         */
    request: function () {
        return this.owner.request.apply(this.owner, arguments);
    }
});
// 扩展Uploader.
$.extend(Uploader.prototype, {
    /**
         * @property {String | Array} [disableWidgets=undefined]
         * @namespace options
         * @for Uploader
         * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。
         */
    // 覆写_init用来初始化widgets
    _init: function () {
        var me = this, widgets = me._widgets = [], deactives = me.options.disableWidgets || '';
        $.each(widgetClass, function (_, klass) {
            (!deactives || !~deactives.indexOf(klass._name)) && widgets.push(new klass(me));
        });
        return _init.apply(me, arguments);
    },
    request: function (apiName, args, callback) {
        var i = 0, widgets = this._widgets, len = widgets && widgets.length, rlts = [], dfds = [], widget, rlt, promise, key;
        args = isArrayLike(args) ? args : [args];
        for (; i < len; i++) {
            widget = widgets[i];
            rlt = widget.invoke(apiName, args);
            if (rlt !== IGNORE) {
                // Deferred对象
                if (Base.isPromise(rlt)) {
                    dfds.push(rlt);
                } else {
                    rlts.push(rlt);
                }
            }
        }
        // 如果有callback，则用异步方式。
        if (callback || dfds.length) {
            promise = Base.when.apply(Base, dfds);
            key = promise.pipe ? 'pipe' : 'then';
            // 很重要不能删除。删除了会死循环。
            // 保证执行顺序。让callback总是在下一个 tick 中执行。
            return promise[key](function () {
                var deferred = Base.Deferred(), args = arguments;
                if (args.length === 1) {
                    args = args[0];
                }
                setTimeout(function () {
                    deferred.resolve(args);
                }, 1);
                return deferred.promise();
            })[callback ? key : 'done'](callback || Base.noop);
        } else {
            return rlts[0];
        }
    },
    destroy: function () {
        _destroy.apply(this, arguments);
        this._widgets = null;
    }
});
/**
     * 添加组件
     * @grammar Uploader.register(proto);
     * @grammar Uploader.register(map, proto);
     * @param  {object} responseMap API 名称与函数实现的映射
     * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义
     * @method Uploader.register
     * @for Uploader
     * @example
     * Uploader.register({
     *     'make-thumb': 'makeThumb'
     * }, {
     *     init: function( options ) {},
     *     makeThumb: function() {}
     * });
     *
     * Uploader.register({
     *     'make-thumb': function() {
     *         
     *     }
     * });
     */
Uploader.register = Widget.register = function (responseMap, widgetProto) {
    var map = {
            init: 'init',
            destroy: 'destroy',
            name: 'anonymous'
        }, klass;
    if (arguments.length === 1) {
        widgetProto = responseMap;
        // 自动生成 map 表。
        $.each(widgetProto, function (key) {
            if (key[0] === '_' || key === 'name') {
                key === 'name' && (map.name = widgetProto.name);
                return;
            }
            map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;
        });
    } else {
        map = $.extend(map, responseMap);
    }
    widgetProto.responseMap = map;
    klass = Base.inherits(Widget, widgetProto);
    klass._name = map.name;
    widgetClass.push(klass);
    return klass;
};
/**
     * 删除插件，只有在注册时指定了名字的才能被删除。
     * @grammar Uploader.unRegister(name);
     * @param  {string} name 组件名字
     * @method Uploader.unRegister
     * @for Uploader
     * @example
     *
     * Uploader.register({
     *     name: 'custom',
     *     
     *     'make-thumb': function() {
     *         
     *     }
     * });
     *
     * Uploader.unRegister('custom');
     */
Uploader.unRegister = Widget.unRegister = function (name) {
    if (!name || name === 'anonymous') {
        return;
    }
    // 删除指定的插件。
    for (var i = widgetClass.length; i--;) {
        if (widgetClass[i]._name === name) {
            widgetClass.splice(i, 1);
        }
    }
};
module.exports = Widget || module.exports;;